package kawigi.language;

import java.io.File;


/**
 * Class introducing language-dependent features for C#.
 * Class is made as singleton.
 *
 * @see     EditorLanguage
 */
public final class CSharpLang extends EditorLanguage
{
	/**
	 * Single instance of this class
	 */
	private static final CSharpLang inst = new CSharpLang();

	/**
	 * Returns single instance of the class.
	 *
	 * @return      Instance of <code>CSharpLang</code>
	 */
	public static CSharpLang getInstance()
	{
		return inst;
	}

	/**
	 * Default constructor.
	 */
	private CSharpLang()
	{
		super();
		// Fill the map of our type names
		fillTypeNames(getAllTypeNames());
		// And fill all code-generation and local compiling variables which are
		// special for C#.
		sDefaultFileName = "$PROBLEM$.cs";
		sDefaultCompileCommand = "csc $PROBLEM$.cs";
		sDefaultExecuteCommand = '/' == File.separatorChar? "mono $PROBLEM$.exe": "$CWD$\\$PROBLEM$.exe";
	}

	/*
	  ============================================================================
		Common procedures.
	 */
	/**
	 * Returns array of all type names in C#. Type names order is related to
	 * order of values in <code>EditorDataType</code>.
	 *
	 * @return      Array of type names.
	 *
	 * @see         EditorDataType
	 */
	static String[] getAllTypeNames()
	{
		return new String[] {"string", "int", "double", "long", "Boolean", "string[]", "int[]", "double[]", "long[]"};
	}

	/**
	 * Returns the name of this language in lowercase ('csharp').
	 * This name is used in name of category in properties for this language.
	 *
	 * @return      Name of this language - 'csharp'
	 */
	public String toString()
	{
		return "csharp";
	}
	//============================================================================

	/*
	  ============================================================================
		Code related to test code generation.
	 */
	/**
	 * Clears all data stored in class for generating new pack of test code.
	 *
	 * @see     EditorLanguage#clear()
	 */
	protected void clear()
	{
		super.clear();
		indentRight();
	}

	/**
	 * Inserts directive for test region starting and STAThread directive.
	 *
	 * @see     EditorLanguage#preamble()
	 */
	protected void preamble()
	{
		text("#region Testing code generated by KawigiEdit").endLine();
		text("[STAThread]").endLine();
	}

	/**
	 * Inserts directive for test region ending.
	 *
	 * @see     EditorLanguage#postamble()
	 */
	protected void postamble()
	{
		text("#endregion").endLine();
	}

	/**
	 * Function for inserting prefix of function header.
	 *
	 * @param funcRetType   The return type of function
	 * @return              All methods of <code>EditorLanguage</code> related to test code generation
	 *                      return <code>this</code> to make possible convinient call chains
	 *
	 * @see                 EditorLanguage#funcDefPrefix(EditorDataType)
	 * @see                 EditorLanguage#funcDefPostfix(EditorDataType)
	 */
	protected EditorLanguage funcDefPrefix(EditorDataType funcRetType)
	{
		return text("private static ").text(getTypeName(funcRetType)).text(' ');
	}

	/**
	 * Method for adding code of remembering current time.
	 *
	 * @param varName   Name of variable to remember time in.
	 *
	 * @see             EditorLanguage#rememberCurTime(String)
	 */
	protected void rememberCurTime(String varName)
	{
		text("DateTime ").text(varName).text(" = DateTime.Now").endCodeLine();
	}

	/**
	 * Method for adding formula counting difference between two
	 * time points stored in two different variables in seconds (double value).
	 *
	 * @param varStart  Variable name of starting moment
	 * @param varEnd    Variable name of ending moment
	 * @return          All methods of <code>EditorLanguage</code> related to test code generation
	 *                  return <code>this</code> to make possible convinient call chains
	 *
	 * @see             EditorLanguage#timeDiff(String, String)
	 */
	protected EditorLanguage timeDiff(String varStart, String varEnd)
	{
		return text('(').text(varEnd).text(" - ").text(varStart).text(").TotalSeconds");
	}

	/**
	 * Adds header of main procedure.
	 *
	 * @see             EditorLanguage#mainSubDef()
	 */
	protected void mainSubDef()
	{
		text("public static void Main(string[] args) {");
		super.mainSubDef();
	}

	/**
	 * Gets postfix for given data type in C#.
	 *
	 * @param type      Data type to check for postfix.
	 * @return          Postfix string for this type in C++.
	 *
	 * @see             EditorLanguage#getNumTypePostfix(EditorDataType)
	 */
	protected String getNumTypePostfix(EditorDataType type)
	{
		String res;
		if (type.isType(EditorDataType.Double))
	        res = "D";
		else if (type.isType(EditorDataType.Long))
	        res = "L";
		else
			res = super.getNumTypePostfix(type);

		return res;
	}
}
